package com.gupaoedu.design.proxy.custom;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * <p></p>
 *
 * @author Andy
 * @date 2018/3/12.
 */
public class GPProxy implements Serializable {
    public static final String ln = "\r\n";

    public static Object newProxyInstance(GPClassLoader loader, Class<?>[] interfaces, GPInvocationHandler h) throws IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //1、动态生成源代码.java文件
        String src = generateSource(interfaces);

        //2、Java文件输出磁盘
        String filePath = GPProxy.class.getResource("").getPath();
        System.out.println(filePath);
        File file = new File(filePath + "$Proxy0.java");
        FileWriter fw = null;
        try {
            fw = new FileWriter(file);
            fw.write(src);
            fw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != fw) {
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        //3、把生成的.java文件编译成.class文件
        JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileManager = javaCompiler.getStandardFileManager(null, null, null);
        Iterable<? extends JavaFileObject> iterable = fileManager.getJavaFileObjects(file);
        JavaCompiler.CompilationTask task = javaCompiler.getTask(null, fileManager, null, null, null, iterable);
        task.call();
        try {
            fileManager.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        //4、编译生成的.class文件加载到JVM中来
        Class<?> proxyClazz = loader.findClass("$Proxy0");
        Constructor<?> c = proxyClazz.getConstructor(GPInvocationHandler.class);
        file.delete();

        //5、返回字节码重组以后的新的代理对象
        return c.newInstance(h);
    }

    private static String generateSource(Class<?>[] interfaces) {
        StringBuilder src = new StringBuilder();
        src.append("package com.gupaoedu.design.proxy.custom;" + ln);
        src.append("import com.gupaoedu.design.proxy.Person;" + ln);
        src.append("import java.lang.reflect.Method;" + ln);
        src.append("public class $Proxy0 implements " + interfaces[0].getName() + "{" + ln);
            src.append("GPInvocationHandler h;" + ln);
            src.append("public $Proxy0(GPInvocationHandler h){" + ln);
                src.append("this.h = h;");
            src.append("}" + ln);
        for (Method method : interfaces[0].getMethods()) {
            src.append("public " + method.getReturnType().getName() +" "+ method.getName() + "(){" + ln);
                src.append("try{" + ln);
                    src.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + method.getName() + "\",new Class[]{});" + ln);
                    src.append("this.h.invoke(this,m,null);" + ln);
                src.append("}catch(Throwable e){" + ln);
                    src.append("e.printStackTrace();" + ln);
                src.append("}" + ln);
            src.append("}" + ln);

        }
        src.append("}" + ln);
        return src.toString();
    }
}
